package top.heue.utils.lifecycle.helper

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap


private object FlowEventBus {
    private val bus: ConcurrentHashMap<String, MutableSharedFlow<out Any?>> = ConcurrentHashMap()

    private fun formatKey(key: Any) = key.toString()

    @Suppress("UNCHECKED_CAST")
    fun <T : Any?> with(
        key: Any,
        isSticky: Boolean = false,
        onBufferOverflow: BufferOverflow = BufferOverflow.DROP_OLDEST
    ): MutableSharedFlow<T?> {
        val formatKey = formatKey(key)
        if (!bus.containsKey(formatKey)) {
            val flow = MutableSharedFlow<T?>(
                replay = if (isSticky) 1 else 0,
                extraBufferCapacity = Int.MAX_VALUE,
                onBufferOverflow = onBufferOverflow
            )
            bus[formatKey] = flow
        }
        return bus[formatKey] as MutableSharedFlow<T?>
    }

    fun remove(key: Any) {
        val formatKey = formatKey(key)
        bus.remove(formatKey)
    }
}

/**
 * 对外只暴露SharedFlow
 * @param action String
 * @return SharedFlow<T>
 */
fun <T> get(
    action: Any,
    isSticky: Boolean = false,
    onBufferOverflow: BufferOverflow = BufferOverflow.DROP_OLDEST
): SharedFlow<T?> {
    return FlowEventBus.with(action, isSticky, onBufferOverflow)
}

/**
 * 挂起函数
 * @param action String
 * @param data T
 */
suspend fun <T : Any?> post(action: Any, data: T? = null) {
    FlowEventBus.with<T?>(action).emit(data)
}

/**
 * 详见tryEmit和emit的区别
 * @param action String
 * @param data T
 * @return Boolean
 */
fun <T : Any?> tryPost(action: Any, data: T? = null): Boolean {
    return FlowEventBus.with<T?>(action).tryEmit(data)
}

/**
 * sharedFlow会长久持有，所以要加声明周期限定，不然会出现内存溢出
 * @param action String
 * @param block Function1<T, Unit>
 */
suspend fun <T : Any?> Lifecycle.subscribe(action: Any, block: (T?) -> Unit) {
    repeatOnLifecycle(Lifecycle.State.CREATED) {
        FlowEventBus.with<T?>(action).collect {
            block(it)
        }
    }
}

/**
 * sharedFlow会长久持有，所以要加声明周期限定，不然会出现内存溢出
 * @param action String
 * @param block Function1<T, Unit>
 */
fun <T : Any?> ViewModel.subscribe(action: Any, block: (T?) -> Unit) {
    viewModelScope.launch { subscribe<T>(action, block) }
}

/**
 * 注意，使用这个方法需要将协程在合适的时候取消，否则会导致内存溢出
 * @param action String
 * @param block Function1<T, Unit>
 */
suspend fun <T : Any?> subscribe(action: Any, block: (T?) -> Unit) {
    FlowEventBus.with<T?>(action).collect {
        block(it)
    }
}

fun removeSubscribe(key: Any) {
    FlowEventBus.remove(key)
}